home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / hypercrd / xcmds / tffdsply.hqx / TIFFWindow.c < prev    next >
C/C++ Source or Header  |  1993-01-04  |  26KB  |  1,075 lines

  1. /*
  2.  * This software is copyright 1992 by Robert Morris.
  3.  * You may freely redistribute this software as shareware
  4.  * if you do so in the same form as you got it. If you find
  5.  * this software useful, please send $12 to:
  6.  *   Robert Morris
  7.  *   P.O. Box 1044
  8.  *   Harvard Square Station
  9.  *   Cambridge, MA 02238
  10.  *   ecognome@aol.com
  11.  * If you incorporate any of this software in any kind of
  12.  * commercial product, please send $2 per copy distributed
  13.  * to the above address.
  14.  */
  15.  
  16. /*
  17.  * TIFFWindow file, windowStyle, visible, depth, customPalette
  18.  *
  19.  * If no file is supplied, or if the file is "", TIFFWindow prompts the user.
  20.  * It uses hypercard's file search path.
  21.  *
  22.  * WindowStyle has no effect right now.
  23.  *
  24.  * Visible controls whether the window starts out visible.
  25.  *
  26.  * Depth sets the depth of the off-screen buffer; such a buffer greatly improves
  27.  * redraw and scroll speed. 0 means no buffer
  28.  * at all: all drawing is done from the disk. Only 0, 16 and 32 are universal; 1, 2, 4,
  29.  * and 8 only work well if the TIFF image is actually that depth.
  30.  * TIFFWindow will reduce the off-screen depth to the depth of the TIFF image.
  31.  * If there is not enough memory, it won't use an off-screen buffer.
  32.  *
  33.  * CustomPalette is true, a cpmt resource number, or false. The default is true,
  34.  * which causes TIFFWindow to call the Picture Utilities to compute a reasonable
  35.  * palette for the deepest CLUT screen at the time when TIFFWindow is called.
  36.  * A number indicates the resource number of a custom sampling method.
  37.  * False means use the color map in the TIFF file, or none if there was none.
  38.  * Computing a palette can take a few seconds. Custom palettes only work with
  39.  * an off-screen buffer.
  40.  *
  41.  * If the result is not empty, it contains an error message. TIFFWindow usually
  42.  * produces an error message if it doesn't understand the TIFF file format, but
  43.  * occasionally it doesn't find this out until too late, in which case it will
  44.  * display an empty window.
  45.  *
  46.  * The dithering property controls dithering. This only works well from an off-screen
  47.  * graphics buffer.
  48.  *
  49.  * The scrollbars property controls whether scrollbars are visible.
  50.  *
  51.  * The picturewidth and pictureheight properties yield the size of the image
  52.  * in pixels.
  53.  *
  54.  * The scale property, a number, controls zooming of the image. Each displayed
  55.  * pixel represents a square 2^scale pixels on a side in the original. So, for
  56.  * instance, a scale of 0 (the default) means no change, 1 means double the image
  57.  * size, and -1 means halve it.
  58.  *
  59.  * The picturedepth property yields the pixel depth of the TIFF image.
  60.  *
  61.  * If the user clicks on the picture, TIFFWindow sends to HyperTalk messages,
  62.  * one when the user presses the mouse button, and one when he or she releases
  63.  * the button. The messages are MouseDownInPicture and MouseUpInPicture. The
  64.  * messages have two arguments, the window name and the image coordinates.
  65.  */
  66.  
  67. #include <HyperXCmd.h>
  68. #include <stdlib.h>
  69. #include "SetUpA4.h"
  70. #include <string.h>
  71. #include <ctype.h>
  72. #include "tiffinfo.h"
  73. #include <QDOffscreen.h>
  74. #include <Palette.h>
  75. #include <PictUtil.h>
  76.  
  77. typedef struct thunk{
  78.     TIFFPtr ti;
  79.     CGrafPtr gw; /* off-screen graphics world */
  80.     ControlHandle hScroll, vScroll;
  81.     int ref; /* keep the file open */
  82.     Boolean active;
  83.     
  84.     /* properties */
  85.     Boolean visible;
  86.     Boolean scrollbars;
  87.     int depth; /* desired off-screen depth, or 0 for none */
  88.     int scale;
  89.     Boolean dither;
  90.     Boolean customPalette;
  91.     Boolean customMethod;
  92. } ThunkRec, **Thunk;
  93.  
  94. Thunk th;
  95. WindowPtr w;
  96. XCmdPtr xptr;
  97.  
  98. #define SBWIDTH        15
  99.  
  100. void InitPalette(void);
  101. void DisposeThunk(Thunk);
  102. Handle HStr(char *);
  103. int pstrcmp(StringPtr, StringPtr);
  104. int SetUpWindow(StringPtr);
  105. void UpdateWindow(void);
  106. void DoContent(EventRecord *theEvent);
  107. void MyGrowWindow(Point);
  108. int cmp(char *, char *);
  109. void FileOfPath(StringPtr path, StringPtr file);
  110. OSErr CopyToGWorld();
  111. int FixDepth(int depth);
  112. Boolean SetProp(StringPtr prop, Handle h);
  113. Handle GetProp(StringPtr prop);
  114. int DeepestCLUTScreen();
  115.  
  116. /* there was no GetGWorldPixMap() before System 7 */
  117. #define GWPM(gw) (HasSystem7() ? GetGWorldPixMap(gw) : (gw)->portPixMap)
  118.  
  119. pascal void
  120. main(paramPtr)
  121. XCmdPtr paramPtr;
  122. {
  123.     XWEventInfoPtr ei;
  124.     WindowPtr whichWindow;
  125.     GrafPtr oport;
  126.     int theChar, err, ref, vref, findCode;
  127.     Point pt;
  128.     Rect r;
  129.     char **h;
  130.     StringPtr prop;
  131.     Str255 tmp, fullname, ttl;
  132.     PaletteHandle pltt;
  133.     Thunk oth;
  134.     WindowPtr ow;
  135.     XCmdPtr oxptr;
  136.     SFReply sf;
  137.     SFTypeList types;
  138.     OSType type;
  139.     CGrafPtr agw;
  140.     
  141.     RememberA0();
  142.     SetUpA4();
  143.     
  144.     /* save old values */
  145.     oth = th;
  146.     ow = w;
  147.     oxptr = oxptr;
  148.     
  149.     xptr = paramPtr;
  150.     
  151.     if(paramPtr->paramCount == -1){
  152.         /* it's a window event */
  153.         ei = (XWEventInfoPtr) (paramPtr->params[0]);
  154.         w = ei->eventWindow;
  155.         th = (Thunk) GetWRefCon(w);
  156.         if(th == 0){
  157.             paramPtr->passFlag = TRUE;
  158.             goto out;
  159.         }
  160.         
  161.         GetPort(&oport);
  162.         SetPort(w);
  163.         
  164.         switch(ei->event.what){
  165.         case xOpenEvt:
  166.             XWAllowReEntrancy(paramPtr, w, TRUE, TRUE);
  167.             if((*th)->visible)
  168.                 SelectWindow(w);    /* if I don't do this, it's not highlighted... */
  169.             break;
  170.         case xCloseEvt:
  171.             XWAllowReEntrancy(paramPtr, w, FALSE, FALSE);
  172.             DisposeThunk(th);
  173.             SetWRefCon(w, 0L);
  174.             if(HasColorQD() && (pltt = GetPalette(w))){
  175.                 SetPalette(w, 0L, FALSE);
  176.                 DisposePalette(pltt);
  177.             }
  178.             paramPtr->passFlag = TRUE;    /* yes, we're willing to close */
  179.             break;
  180.         case xCursorWithin:
  181.             paramPtr->passFlag = TRUE;    /* ask HyperCard for an arrow cursor */
  182.             break;
  183.         case xSetPropEvt:
  184.             paramPtr->passFlag = !SetProp((StringPtr)ei->eventParams[0],
  185.                                           (Handle)ei->eventParams[1]);
  186.             break;
  187.         case xGetPropEvt:
  188.             h = GetProp((StringPtr) (ei->eventParams[0]));
  189.             if(h){
  190.                 ei->eventResult = h;
  191.                 paramPtr->passFlag = FALSE;
  192.             } else {
  193.                 paramPtr->passFlag = TRUE;    /* ask HyperCard to handle it for us */
  194.                 ei->eventResult = (char **) 0;
  195.             }
  196.             break;
  197.         case xGiveUpEditEvt:
  198.             EndXWEdit(paramPtr, w);
  199.             break;
  200.         case xEditUndo:
  201.             /* what should I do here? */
  202.             break;
  203.         case xEditCut:
  204.             break;
  205.         case xEditCopy:
  206.             break;
  207.         case xEditPaste:
  208.             break;
  209.         case xEditClear:
  210.             break;
  211.         case nullEvent:
  212.             break;
  213.         case activateEvt:
  214.             if((*th)->scrollbars){
  215.                 if (ei->event.modifiers & activeFlag) {
  216.                     ShowControl((*th)->vScroll);
  217.                     ShowControl((*th)->hScroll);
  218.                     (*th)->active = TRUE;
  219.                 } else {
  220.                     HideControl((*th)->vScroll);
  221.                     HideControl((*th)->hScroll);
  222.                     (*th)->active = FALSE;
  223.                 }
  224.                 DrawGrowIcon(w);
  225.             }
  226.             break;
  227.         case mouseDown:
  228.             switch(findCode = FindWindow(ei->event.where, &whichWindow)){
  229.             case inGoAway:
  230.                 if(TrackGoAway(w, ei->event.where)){
  231.                     CloseXWindow(paramPtr, w);    /* ask HyperCard to close us */
  232.                 }
  233.                 break;
  234.             case inDrag:
  235.                 /*
  236.                  * ask HyperCard to deal with moving the window. this is
  237.                  * an undocumented feature as of B39.
  238.                  */
  239.                 paramPtr->passFlag = TRUE;
  240.                 break;
  241.             case inContent:
  242.                 DoContent(&(ei->event));
  243.                 break;
  244.             case inGrow:
  245.                 MyGrowWindow(ei->event.where);
  246.                 break;
  247.             case inZoomIn:
  248.             case inZoomOut:
  249.                 if(TrackBox(w, ei->event.where, findCode) == TRUE){
  250.                     ZoomWindow(w, findCode, TRUE);
  251.                     FixScrollBars();
  252.                 }
  253.                 break;
  254.             }
  255.             break;
  256.         case keyDown:
  257.         case autoKey: 
  258.             theChar = ei->event.message & charCodeMask;
  259.             if ((ei->event.modifiers & cmdKey) != 0){  
  260.             } else {
  261.             }
  262.             break;
  263.         case updateEvt:
  264.             UpdateWindow();
  265.             break;
  266.         }
  267.         
  268.         SetPort(oport);
  269.     } else {
  270.         th = (Thunk) NewHandle((long) sizeof(**th));
  271.         if(th == 0){
  272.             paramPtr->returnValue = HStr("out of memory");
  273.             goto out;
  274.         }
  275.         (*th)->ref = -1;
  276.         (*th)->ti = 0;
  277.         (*th)->gw = 0;
  278.         (*th)->hScroll = (*th)->vScroll = 0;
  279.         (*th)->active = FALSE;
  280.         (*th)->visible = TRUE;
  281.         (*th)->scrollbars = TRUE;
  282.         (*th)->depth = 32;
  283.         (*th)->dither = FALSE;
  284.         (*th)->scale = 0;
  285.         (*th)->customPalette = TRUE;
  286.         (*th)->customMethod = systemMethod;
  287.         
  288.         if(paramPtr->paramCount > 2 && cmp(*(paramPtr->params[2]), "true") != 1)
  289.             (*th)->visible = FALSE;
  290.             
  291.         if(paramPtr->paramCount > 3)
  292.             (*th)->depth = FixDepth(atoi(*(paramPtr->params[3])));
  293.             
  294.         if(paramPtr->paramCount > 4){
  295.             if(cmp(*(paramPtr->params[4]), "true")){
  296.                 (*th)->customPalette = TRUE;
  297.                 (*th)->customMethod = systemMethod;
  298.             } else if(cmp(*(paramPtr->params[4]), "false")){
  299.                 (*th)->customPalette = FALSE;
  300.             } else {
  301.                 (*th)->customPalette = TRUE;
  302.                 (*th)->customMethod = atoi(*(paramPtr->params[4]));
  303.             }
  304.         }
  305.         
  306.         if(paramPtr->paramCount > 0 && (*(paramPtr->params[0]))[0] != '\0'){
  307.             strncpy((char *)tmp, *(paramPtr->params[0]), sizeof(tmp) - 1);
  308.             CtoPstr(tmp);
  309.             types[0] = 'TIFF';
  310.             type = 'TIFF';
  311.             if(GetFilePath(xptr, tmp, 1, types, TRUE, &type, fullname) != TRUE){
  312.                 paramPtr->returnValue = HStr("cannot find file");
  313.                 goto out;
  314.             }
  315.             err = FSOpen(fullname, 0, &ref);
  316.             FileOfPath(fullname, ttl);
  317.         } else {
  318.             pt.h = pt.v = 75;
  319.             types[0] = 'TIFF';
  320.             SFGetFile(pt, "\pWhat TIFF file?", 0L, 1, types, 0L, &sf);
  321.             if(sf.good == 0){
  322.                 paramPtr->returnValue = HStr("cancel");
  323.                 goto out;
  324.             }
  325.             err = FSOpen(sf.fName, sf.vRefNum, &ref);
  326.             FileOfPath(sf.fName, ttl);
  327.         }
  328.         if(err != 0){
  329.             DisposeThunk(th);
  330.             paramPtr->returnValue = HStr("cannot open file");
  331.             goto out;
  332.         }
  333.         (*th)->ref = ref;
  334.         
  335.         (*th)->ti = ScanTIFF((*th)->ref);
  336.         if((*th)->ti == 0 || GetTIFFError((*th)->ti, tmp) != 0){
  337.             DisposeThunk(th);
  338.             paramPtr->returnValue = HStr("cannot understand TIFF file");
  339.             goto out;
  340.         }
  341.         
  342.         if(TIFFDrawable((*th)->ti) == FALSE){
  343.             DisposeThunk(th);
  344.             paramPtr->returnValue = HStr("Cannot draw the picture on this Macintosh.");
  345.             goto out;
  346.         }
  347.         
  348.         /* attempt to set up an off-screen copy */
  349.         if((*th)->depth > 0 && HasQD32()){
  350.             /* eliminate excess depth */
  351.             if((*th)->ti->samplesPerPixel == 1 &&
  352.                (*th)->ti->bitsPerSample[0] < (*th)->depth){
  353.                 (*th)->depth = FixDepth((*th)->ti->bitsPerSample[0]);
  354.             }
  355.             
  356.             r.left = 0;
  357.             r.right = (*th)->ti->imageWidth;
  358.             r.top = 0;
  359.             r.bottom = (*th)->ti->imageLength;
  360.             
  361.             err = NewGWorld(&agw, (*th)->depth, &r, (*th)->ti->colorMap, 0L, 0);
  362.             if(err == 0){
  363.                 (*th)->gw = agw;
  364.                 if((err = CopyToGWorld()) != 0){
  365.                     if(GetTIFFError((*th)->ti, tmp) != 0 && tmp[0] != 0)
  366.                         paramPtr->returnValue = PasToZero(xptr, tmp);
  367.                     else if(err == memFullErr)
  368.                         paramPtr->returnValue = HStr("out of memory");
  369.                     else
  370.                         paramPtr->returnValue = HStr("could not understand TIFF file");
  371.                     DisposeThunk(th);
  372.                     goto out;
  373.                 }
  374.                 FSClose((*th)->ref);
  375.                 (*th)->ref = -1;
  376.             }
  377.         }
  378.         
  379.         if(SetUpWindow(ttl) < 0){
  380.             DisposeThunk(th);
  381.             paramPtr->returnValue = HStr("window creation failed");
  382.             goto out;
  383.         }
  384.     
  385.         InitPalette();
  386.     }
  387.     
  388. out:
  389.     /* restore old globals in case of reentrance */
  390.     xptr = oxptr;
  391.     w = ow;
  392.     th = oth;
  393.     
  394.     RestoreA4();
  395. }
  396.  
  397. OSErr
  398. CopyToGWorld()
  399. {
  400.     CGrafPtr oldPort;
  401.     GDHandle oldGD;
  402.     PixMapHandle pm;
  403.     OSErr err;
  404.     Rect r;
  405.  
  406.     GetGWorld(&oldPort, &oldGD);
  407.     
  408.     SetGWorld((*th)->gw, 0);
  409.     pm = GWPM((*th)->gw);
  410.     if(LockPixels(pm) != TRUE){
  411.         SetGWorld(oldPort, oldGD);
  412.         return(memFullErr);
  413.     }
  414.  
  415.     r = (*th)->gw->portRect;
  416.     err = DrawTIFF((*th)->ref, (*th)->ti, r, r, 0);
  417.  
  418.     UnlockPixels(pm);
  419.     SetGWorld(oldPort, oldGD);
  420.     
  421.     return(err);
  422. }
  423.  
  424. void
  425. DisposeThunk(Thunk th)
  426. {
  427.     if(th){
  428.         if((*th)->ti)
  429.             DisposeTIFF((*th)->ti);
  430.         (*th)->ti = 0;
  431.         if((*th)->ref != -1)
  432.             FSClose((*th)->ref);
  433.         (*th)->ref = -1;
  434.         if((*th)->gw)
  435.             DisposeGWorld((*th)->gw);
  436.         (*th)->gw = 0;
  437.         DisposHandle(th);
  438.     }
  439. }
  440.  
  441. /*
  442.  * returns < 0 if there was a problem.
  443.  */
  444. int
  445. SetUpWindow(StringPtr ttl)
  446. {
  447.     Rect wr, sr, r;
  448.     GDHandle gd;
  449.     int iheight, iwidth, wwidth, wheight;
  450.     GrafPtr wmport;
  451.     
  452.     /*
  453.      * Choose a window size: try to show the whole image, but stay on
  454.      * the screen.
  455.      */
  456.     if(HasColorQD()){
  457.         gd = GetMainDevice();
  458.         sr = (*gd)->gdRect;
  459.     } else {
  460.         GetWMgrPort(&wmport);
  461.         sr = wmport->portRect;
  462.     }
  463.     
  464.     iwidth = (*th)->ti->imageWidth;
  465.     iheight = (*th)->ti->imageLength;
  466.     
  467. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  468.     wwidth = MIN(iwidth+SBWIDTH, sr.right - sr.left - 40);
  469.     wheight = MIN(iheight+SBWIDTH, sr.bottom - sr.top - 70);
  470.  
  471.     wr.left = ((sr.right - sr.left) / 2) - (wwidth / 2);
  472.     wr.right = wr.left + wwidth;
  473.     wr.top = ((sr.bottom - sr.top - 30) / 2) - (wheight / 2) + 30;
  474.     wr.bottom = wr.top + wheight;
  475.     
  476.     w = NewXWindow(xptr,
  477.                     &wr,
  478.                     ttl,             /* title */
  479.                     (*th)->visible,
  480.                     documentProc,
  481.                     HasColorQD(),    /* color? */
  482.                     FALSE);            /* floating? */
  483.                         
  484.                          
  485.     if(w == 0)
  486.         return(-1);
  487.         
  488.     SetWRefCon(w, (long)th);
  489.         
  490.     r.right = wr.right;
  491.     r.left = r.right - SBWIDTH;
  492.     r.top = wr.top;
  493.     r.bottom = wr.bottom;
  494.     (*th)->vScroll = NewControl(w, &r, "", TRUE, 0, 0, 1, scrollBarProc, 0L);
  495.         
  496.     r.left = wr.left;
  497.     r.right = wr.right;
  498.     r.bottom = wr.bottom;
  499.     r.top = r.bottom - SBWIDTH;
  500.     (*th)->hScroll = NewControl(w, &r, "", TRUE, 0, 0, 1, scrollBarProc, 0L);
  501.     
  502.     FixScrollBars();
  503.     
  504.     return(0);
  505. }
  506.  
  507. /*
  508.  * the window has changed size, and the scroll bars will have to be
  509.  * resized, and their max and min values re-set.
  510.  */
  511. FixScrollBars()
  512. {
  513.     Rect wr, r;
  514.     int oh, ov, iheight, iwidth, wheight, wwidth;
  515.     
  516.     wr = w->portRect;
  517.     
  518.     iheight = (*th)->ti->imageLength;
  519.     iwidth = (*th)->ti->imageWidth;
  520.     
  521.     HideControl((*th)->vScroll);
  522.     HideControl((*th)->hScroll);
  523.     
  524.     oh = GetCtlValue((*th)->hScroll);
  525.     ov = GetCtlValue((*th)->vScroll);
  526.     
  527. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  528.     wheight = UnScaleIt(wr.bottom - wr.top - ((*th)->scrollbars ? SBWIDTH : 0));
  529.     SetCtlMin((*th)->vScroll, 0);
  530.     SetCtlMax((*th)->vScroll, MAX(0, iheight - wheight));
  531.     
  532.     wwidth = UnScaleIt(wr.right - wr.left - ((*th)->scrollbars ? SBWIDTH : 0));
  533.     SetCtlMin((*th)->hScroll, 0);
  534.     SetCtlMax((*th)->hScroll, MAX(0, iwidth - wwidth));
  535.     
  536.     if(oh != GetCtlValue((*th)->hScroll) || ov != GetCtlValue((*th)->vScroll)){
  537.         InvalRect(&(w->portRect));
  538.     }
  539.     
  540.     MoveControl((*th)->vScroll, wr.right - SBWIDTH, wr.top - 1);
  541.     SizeControl((*th)->vScroll, SBWIDTH+1, wr.bottom - wr.top - SBWIDTH + 2);
  542.     
  543.     MoveControl((*th)->hScroll, wr.left - 1, wr.bottom - SBWIDTH);
  544.     SizeControl((*th)->hScroll, wr.right - wr.left - SBWIDTH + 2, SBWIDTH+1);
  545.     
  546.     if((*th)->scrollbars){
  547.         if((*th)->active){
  548.             ShowControl((*th)->vScroll);
  549.             ShowControl((*th)->hScroll);
  550.             DrawGrowIcon(w);
  551.         }
  552.     }
  553. }
  554.  
  555. int
  556. UnScaleIt(x)
  557. int x;
  558. {
  559.     int i;
  560.     
  561.     if((*th)->scale > 0){
  562.         for(i = 0; i < (*th)->scale; i++)
  563.             x /= 2;
  564.     } else if((*th)->scale < 0){
  565.         for(i = 0; i > (*th)->scale; --i)
  566.             x *= 2;
  567.     }
  568.     
  569.     return(x);
  570. }
  571.  
  572. int
  573. ScaleIt(x)
  574. int x;
  575. {
  576.     int i;
  577.     
  578.     /* calculate how to scale the picture */
  579.     if((*th)->scale > 0){
  580.         for(i = 0; i < (*th)->scale; i++)
  581.             x *= 2;
  582.     } else if((*th)->scale < 0){
  583.         for(i = 0; i > (*th)->scale; --i)
  584.             x /= 2;
  585.     }
  586.     
  587.     return(x);
  588. }
  589.  
  590. void
  591. UpdateWindow()
  592. {
  593.     BeginUpdate( w );
  594.     
  595.     DrawControls( w );
  596.     if((*th)->scrollbars)
  597.         DrawGrowIcon( w );
  598.     ReDraw();
  599.     
  600.     EndUpdate( w );
  601. }
  602.  
  603. ReDraw()
  604. {
  605.     Rect ir, dr, gr;
  606.     int xoff, yoff, dh, dv;
  607.     PixMapHandle pm;
  608.     
  609.     xoff = GetCtlValue((*th)->hScroll);
  610.     yoff = GetCtlValue((*th)->vScroll);
  611.     
  612.     ir.left = xoff;
  613.     ir.top = yoff;
  614.     ir.right = (*th)->ti->imageWidth;
  615.     ir.bottom = (*th)->ti->imageLength;
  616.     
  617.     dr = w->portRect;
  618.     dr.right = dr.left + ScaleIt(ir.right - ir.left);
  619.     dr.bottom = dr.top + ScaleIt(ir.bottom - ir.top);
  620.         
  621.     dh = dr.right - (w->portRect.right - ((*th)->scrollbars ? SBWIDTH : 0));
  622.     if(dh > 0){
  623.         dr.right -= dh;
  624.         ir.right -= UnScaleIt(dh);
  625.     }
  626.     dv = dr.bottom - (w->portRect.bottom - ((*th)->scrollbars ? SBWIDTH : 0));
  627.     if(dv > 0){
  628.         dr.bottom -= dv;
  629.         ir.bottom -= UnScaleIt(dv);
  630.     }
  631.  
  632.     if((*th)->gw){
  633.         pm = GWPM((*th)->gw);
  634.         LockPixels(pm);
  635.         CopyBits(*pm, &(w->portBits), &ir, &dr,
  636.                  (*th)->dither ? 64 : srcCopy, 0L);
  637.         UnlockPixels(pm);
  638.     } else if((*th)->ref != -1){
  639.         DrawTIFF((*th)->ref, (*th)->ti, ir, dr, (*th)->dither);
  640.     }
  641.     
  642.     /* now gray out invalid parts of the window */
  643.     gr.left = dr.right;
  644.     gr.right = w->portRect.right - ((*th)->scrollbars ? SBWIDTH : 0);
  645.     gr.top = 0;
  646.     gr.bottom = w->portRect.bottom - ((*th)->scrollbars ? SBWIDTH : 0);
  647.     FillRect(&gr, &gray);
  648.     
  649.     gr.left = 0;
  650.     gr.top = dr.bottom;
  651.     FillRect(&gr, &gray);
  652. }
  653.  
  654. /*
  655.  * Give the window an appropriate palette. Such a palette should have a separate
  656.  * set of colors for each different depth CLUT device the window intersects.
  657.  * This is possible using inhibited entries, but would be expensive since it
  658.  * would require multiple calls to GetPixMapInfo(). And the palette might have
  659.  * to be recomputed whenever the user moves the window onto a different screen
  660.  * or changes the depth with the Monitors control panel.
  661.  *
  662.  * It would be nice if the color sampling methods used by GetPixMapInfo() returned
  663.  * a palette with the most important colors first, or with multiple sets of
  664.  * inhibited colors; such a palette would be useful at multiple depths.
  665.  *
  666.  * This routine computes a palette for the deepest CLUT device existing at the
  667.  * time the TIFF window was created. This isn't perfect; the user might put
  668.  * the window on a shallower screen, or change the depth.
  669.  *
  670.  * InitPalette the color map in the TIFF file if it can. Otherwise it uses the
  671.  * Picture Utilities. The sampling method cpmt resource number can be set with
  672.  * the 5th argument to TIFFWindow.
  673.  */
  674. void
  675. InitPalette()
  676. {
  677.     CTabHandle cth;
  678.     PaletteHandle pltt = 0, opltt;
  679.     PictInfo pi;
  680.     PixMapHandle pm;
  681.     OSErr err;
  682.     int deepest, size;
  683.         
  684.     if(HasColorQD() == 0)
  685.         return;
  686.         
  687.     deepest = DeepestCLUTScreen();
  688.     size = DepthToSize(deepest);
  689.     
  690.     /*
  691.      * Don't bother if there are no color CLUT screens.
  692.      */
  693.     if(deepest <= 1)
  694.         return;
  695.     
  696.     if((cth = (*th)->ti->colorMap) && ((*cth)->ctSize+1) <= size){
  697.         /*
  698.          * Use the color map in the TIFF file if it isn't too large.
  699.          */
  700.         pltt = NewPalette((*cth)->ctSize + 1, cth, pmTolerant, 0);
  701.     } else if(((*th)->ti->samplesPerPixel > 1 || (*th)->ti->bitsPerSample[0] > 1) &&
  702.               (*th)->customPalette && (*th)->gw && HasSystem7()){
  703.         pm = GWPM((*th)->gw);
  704.         if(LockPixels(pm) == TRUE){
  705.             err = GetPixMapInfo(pm, &pi, returnPalette|suppressBlackAndWhite,
  706.                                 size - 2, (*th)->customMethod, 0);
  707.             if(err == 0){
  708.                 pltt = pi.thePalette;
  709.                 pi.thePalette = 0;
  710.             }
  711.             UnlockPixels(pm);
  712.         }
  713.     }
  714.     
  715.     if(pltt)
  716.         SetPalette(w, pltt, TRUE);
  717. }
  718.  
  719. /*
  720.  * Return the depth of the deepest CLUT screen, or zero if there are no
  721.  * CLUT screens.
  722.  */
  723. int
  724. DeepestCLUTScreen()
  725. {
  726.     GDHandle gd;
  727.     int depth = 0;
  728.     PixMapHandle pm;
  729.     
  730.     gd = GetDeviceList();
  731.     while(gd){
  732.         if(TestDeviceAttribute(gd, screenDevice) == TRUE &&
  733.            TestDeviceAttribute(gd, screenActive) == TRUE &&
  734.            (*gd)->gdType == 0){
  735.             pm = (*gd)->gdPMap;
  736.             if(pm && (*pm)->cmpCount == 1 && (*pm)->cmpSize > depth)
  737.                 depth = (*pm)->cmpSize;
  738.         }
  739.         gd = GetNextDevice(gd);
  740.     }
  741.     
  742.     return(depth);
  743. }
  744.  
  745. int
  746. DepthToSize(int depth)
  747. {
  748.     switch(depth){
  749.     case 1: return(2);
  750.     case 2: return(4);
  751.     case 4: return(16);
  752.     default: return(256);
  753.     }
  754. }
  755.  
  756. pascal void
  757. TrackIt(ctl, part)
  758. ControlHandle ctl;
  759. int part;
  760. {
  761.     int amount, pagesize;
  762.     
  763.     if(ctl == (*th)->hScroll)
  764.         pagesize = UnScaleIt((w->portRect.right - w->portRect.left) / 2);
  765.     else
  766.         pagesize = UnScaleIt((w->portRect.bottom - w->portRect.top) / 2);
  767.         
  768.     switch (part){
  769.     case inUpButton: 
  770.         amount = -4;
  771.         break;
  772.     case inDownButton: 
  773.         amount = 4;
  774.         break;
  775.     case inPageUp: 
  776.         amount = -pagesize;
  777.         break;
  778.     case inPageDown: 
  779.         amount = pagesize;
  780.         break;
  781.     default:
  782.         return;
  783.     }
  784.     
  785.     SetCtlValue(ctl, GetCtlValue(ctl) + amount);
  786.     ReDraw();
  787. }
  788.  
  789. void
  790. DoContent(EventRecord    *theEvent)
  791. {
  792.     Point pt;
  793.     ControlHandle ctl;
  794.     int part, x, y;
  795.     char tmp[256], ttl[256];
  796.     
  797.     if (w != FrontDocWindow(xptr)){
  798.         SelectWindow(w);
  799.         return;
  800.     }
  801.     
  802.     pt = theEvent->where;
  803.     GlobalToLocal(&pt);
  804.     part = FindControl(pt, w, &ctl);
  805.     if(part == inThumb){
  806.         part = TrackControl(ctl, pt, 0L);
  807.         if(part)
  808.             ReDraw();
  809.     } else if(part != 0){
  810.         part = TrackControl(ctl, pt, TrackIt);
  811.     } else {
  812.         x = UnScaleIt(pt.h - w->portRect.left) + GetCtlValue((*th)->hScroll);
  813.         y = UnScaleIt(pt.v - w->portRect.top) + GetCtlValue((*th)->vScroll);
  814.         GetWTitle(w, ttl);
  815.         PtoCstr(ttl);
  816.         sprintf(tmp, "mouseDownInPicture \"%.150s\", \"%d,%d\"",
  817.                      ttl, x, y);
  818.         CtoPstr(tmp);
  819.         SendCardMessage(xptr, (StringPtr)tmp);
  820.         
  821.         while(StillDown() == TRUE)
  822.             ;
  823.             
  824.         GetMouse(&pt);
  825.         x = UnScaleIt(pt.h - w->portRect.left) + GetCtlValue((*th)->hScroll);
  826.         y = UnScaleIt(pt.v - w->portRect.top) + GetCtlValue((*th)->vScroll);
  827.         sprintf(tmp, "mouseUpInPicture \"%.150s\", \"%d,%d\"",
  828.                      ttl, x, y);
  829.         CtoPstr(tmp);
  830.         SendCardMessage(xptr, (StringPtr)tmp);
  831.     }
  832. }
  833.  
  834. void
  835. MyGrowWindow(p)
  836. Point p;
  837. {
  838.     long    theResult;
  839.     Rect     r;
  840.     int iwidth, iheight;
  841.     
  842.     iwidth = (*th)->ti->imageWidth;
  843.     iheight = (*th)->ti->imageLength;
  844.  
  845.     SetRect(&r, 80, 80,
  846.             ScaleIt(iwidth) + 1 +
  847.              ((*th)->scrollbars ? SBWIDTH : 0),
  848.             ScaleIt(iheight) + 1 +
  849.              ((*th)->scrollbars ? SBWIDTH : 0));
  850.     theResult = GrowWindow( w, p, &r );
  851.     if (theResult == 0)
  852.         return;
  853.     
  854.     if((*th)->scrollbars){
  855.         /* we want to make sure the old grow box is redrawn */
  856.         r = w->portRect;
  857.         r.left = r.right - SBWIDTH;
  858.         r.top = r.bottom - SBWIDTH;
  859.         InvalRect(&r);
  860.         EraseRect(&r);
  861.     }
  862.  
  863.     SizeWindow( w, LoWord(theResult), HiWord(theResult), TRUE);
  864.     FixScrollBars();
  865. }
  866.  
  867. /* case-insensitive pascal string compare */
  868. int
  869. pstrcmp(StringPtr a, StringPtr b)
  870. {
  871.     int alen, blen;
  872.     
  873.     if(EqualString(a, b, FALSE, FALSE) == TRUE)
  874.         return(0);
  875.     return(1);
  876. }
  877.  
  878. /* case-insensitive C string compare; returns 1 if equal */
  879. int
  880. cmp(char *a, char *b)
  881. {
  882.     int i, ac, bc;
  883.     
  884.     for(i = 0; a[i] && b[i]; i++){
  885.         ac = a[i];
  886.         if(isupper(ac))
  887.             ac = tolower(ac);
  888.         bc = b[i];
  889.         if(isupper(bc))
  890.             bc = tolower(bc);
  891.         if(ac != bc)
  892.             return(0);
  893.     }
  894.     if(a[i] == b[i])
  895.         return(1);
  896.     return(0);
  897. }
  898.  
  899. Handle
  900. HStr(str)
  901. char *str;
  902. {
  903.     Handle newHndl;
  904.     
  905.     newHndl = (Handle) NewHandle((long) strlen(str) + 1);
  906.     if(newHndl == 0)
  907.         return(0);
  908.     strcpy((char *) (*newHndl), str);
  909.     return(newHndl);
  910. }
  911.  
  912. void
  913. FileOfPath(StringPtr path, StringPtr file)
  914. {
  915.     int i, len;
  916.     
  917.     /* search backwards for the last : */
  918.     for(i = path[0] - 1; i >= 0; --i){
  919.         if(path[i+1] == ':'){
  920.             len = path[0] - i - 1;
  921.             strncpy((char *) file+1, (char *)path + i + 2, len);
  922.             file[0] = len;
  923.             return;
  924.         }
  925.     }
  926.     
  927.     strncpy((char *)file+1, (char *)path+1, path[0]);
  928.     file[0] = path[0];
  929. }
  930.  
  931. /*
  932.  * Take whatever depth the user provided and round it up to the nearest
  933.  * legal QuickDraw depth.
  934.  */
  935. int
  936. FixDepth(int depth)
  937. {
  938.     if(depth < 1)
  939.         return(0);
  940.     if(depth <= 1)
  941.         return(1);
  942.     if(depth <= 2)
  943.         return(2);
  944.     if(depth <= 4)
  945.         return(4);
  946.     if(depth <= 8)
  947.         return(8);
  948.     if(depth <= 16)
  949.         return(16);
  950.     return(32);
  951. }
  952.  
  953. /*
  954.  * Returns TRUE if it could handle the property.
  955.  */
  956. Boolean
  957. SetProp(StringPtr prop, Handle h)
  958. {
  959.     Boolean handled = TRUE;
  960.     Rect r;
  961.     Point pt;
  962.     Str255 tmp;
  963.     int nscale, ndither;
  964.     
  965.     MoveHHi(h);
  966.     HLock(h);
  967.     
  968.     if(pstrcmp(prop, "\pdithering") == 0){
  969.         ndither = cmp(*h, "true");
  970.         if(HasQD32() == 0)
  971.             ndither = FALSE;
  972.         if(ndither != (*th)->dither){
  973.             (*th)->dither = ndither;
  974.             ReDraw();
  975.         }
  976.     } else if(pstrcmp(prop, "\pscrollbars") == 0){
  977.         int nscrollbars = cmp(*h, "true");
  978.         if((*th)->scrollbars != nscrollbars){
  979.             (*th)->scrollbars = nscrollbars;
  980.             r = w->portRect;
  981.             if(nscrollbars == TRUE){
  982.                 /* make room for them */
  983.                 SizeWindow(w, r.right - r.left + SBWIDTH,
  984.                            r.bottom - r.top + SBWIDTH, TRUE);
  985.             } else {
  986.                 /* get rid of them */
  987.                 SizeWindow(w, r.right - r.left - SBWIDTH,
  988.                            r.bottom - r.top - SBWIDTH, TRUE);
  989.             }
  990.             FixScrollBars();
  991.         }
  992.     } else if(pstrcmp(prop, "\pscale") == 0){
  993.         nscale = atoi(*h);
  994.         if(nscale > 5)
  995.             nscale = 5;
  996.         if(nscale < -5)
  997.             nscale = -5;
  998.         if(nscale != (*th)->scale){
  999.             (*th)->scale = nscale;
  1000.             FixScrollBars();
  1001.             ReDraw();
  1002.         }
  1003.     } else if(pstrcmp(prop, "\pscroll") == 0){
  1004.         ZeroToPas(xptr, *h, tmp);
  1005.         StrToPoint(xptr, tmp, &pt);
  1006.         SetCtlValue((*th)->hScroll, pt.h);
  1007.         SetCtlValue((*th)->vScroll, pt.v);
  1008.         ReDraw();
  1009.     } else if(pstrcmp(prop, "\pglobalrect") == 0){
  1010.         ZeroToPas(xptr, *h, tmp);
  1011.         StrToRect(xptr, tmp, &r);
  1012.         MoveWindow(w, r.left, r.top, FALSE);
  1013.         SizeWindow(w, r.right - r.left, r.bottom - r.top, TRUE);
  1014.         FixScrollBars();
  1015.     } else if(pstrcmp(prop, "\pgloballoc") == 0){
  1016.         ZeroToPas(xptr, *h, tmp);
  1017.         StrToPoint(xptr, tmp, &pt);
  1018.         MoveWindow(w, pt.h, pt.v, FALSE);
  1019.     } else
  1020.         handled = FALSE;
  1021.         
  1022.     HUnlock(h);
  1023.     return(handled);
  1024. }
  1025.  
  1026. Handle
  1027. GetProp(StringPtr prop)
  1028. {
  1029.     Handle h = 0;
  1030.     Point pt;
  1031.     Rect r;
  1032.     Str255 tmp;
  1033.     
  1034.     /* hypercard deals with loc and visible */
  1035.     if(pstrcmp(prop, "\pdithering") == 0){
  1036.         h = HStr((*th)->dither ? "true" : "false");
  1037.     } else if(pstrcmp(prop, "\pscrollbars") == 0){
  1038.         h = HStr((*th)->scrollbars ? "true" : "false");
  1039.     } else if(pstrcmp(prop, "\pglobalrect") == 0){
  1040.         pt.h = w->portRect.left;
  1041.         pt.v = w->portRect.top;
  1042.         LocalToGlobal(&pt);
  1043.         r.left = pt.h;
  1044.         r.top = pt.v;
  1045.         r.right = r.left + (w->portRect.right - w->portRect.left);
  1046.         r.bottom = r.top + (w->portRect.bottom - w->portRect.top);
  1047.         RectToStr(xptr, &r, tmp);
  1048.         h = PasToZero(xptr, tmp);
  1049.     } else if(pstrcmp(prop, "\pgloballoc") == 0){
  1050.         pt.h = w->portRect.left;
  1051.         pt.v = w->portRect.top;
  1052.         LocalToGlobal(&pt);
  1053.         PointToStr(xptr, pt, tmp);
  1054.         h = PasToZero(xptr, tmp);
  1055.     } else if(pstrcmp(prop, "\pscroll") == 0){
  1056.         pt.h = GetCtlValue((*th)->hScroll);
  1057.         pt.v = GetCtlValue((*th)->vScroll);
  1058.         PointToStr(xptr, pt, tmp);
  1059.         h = PasToZero(xptr, tmp);
  1060.     } else if(pstrcmp(prop, "\ppicturewidth") == 0){
  1061.         NumToString((long) (*th)->ti->imageWidth, tmp);
  1062.         h = PasToZero(xptr, tmp);
  1063.     } else if(pstrcmp(prop, "\ppictureheight") == 0){
  1064.         NumToString((long) (*th)->ti->imageLength, tmp);
  1065.         h = PasToZero(xptr, tmp);
  1066.     } else if(pstrcmp(prop, "\pscale") == 0){
  1067.         NumToString((long) (*th)->scale, tmp);
  1068.         h = PasToZero(xptr, tmp);
  1069.     } else if(pstrcmp(prop, "\ppicturedepth") == 0){
  1070.         NumToString((long)(*th)->ti->samplesPerPixel * (*th)->ti->bitsPerSample[0], tmp);
  1071.         h = PasToZero(xptr, tmp);
  1072.     }
  1073.     
  1074.     return(h);
  1075. }